% !TeX program = xelatex 
\documentclass[xcolor=svgnames,10pt,UTF8]{ctexbeamer}
%\documentclass[aspectratio=169,xcolor=svgnames,10pt]{beamer}

\RequirePackage{slide}

\logo{\includegraphics[scale=0.02]{../figure/logo.jpg}}
\title{SystemVerilog芯片验证}
\subtitle{第4章~接口}
%\author{王旭}
%\institute{深圳信息职业技术学院~微电子学院}
%\date{\today}

\begin{document}

\frame{\titlepage}
\LogoOn
\LogoOff

\section{接口的定义和使用} \label{The Interface Construct}

\subsection{使用接口简化连接} \label{Using an Interface to Simplify Connections}

\begin{frame}[t,fragile]{接口（interface）的定义和使用}
	\begin{enumerate}
		\item 统一管理一组信号，简化测试模块与DUT的连接。
		\item 接口主要为测试平台服务，不能被逻辑综合。
		\item 接口是静态类型DUT与自动类型对象的通信桥梁（虚接口）。
	\end{enumerate}

	\begin{figure}[!htb]
		\centering%\captionsetup{font={small}}\small %small or scriptsize
		\scalebox{1.0}{
			\begin{tikzpicture}
				\tikzstyle{every node}=[font=\normalsize]
				%\draw[step=1,color=gray!40] (0,0) grid (8,4);
				\begin{pgfonlayer}{background}
					\node[thick,draw,fill=gray!10,rectangle,minimum height=3cm,minimum width=8cm] (Top) at (3.5,0.7) {};
					\node[] at (6,-0.2) {顶层模块};
				\end{pgfonlayer}
				\begin{pgfonlayer}{main}
					\node[thick,draw,fill=red!20,rectangle,minimum height=1.5cm,minimum width=2cm] (Test) at (1,1) {测试模块};
					\node[thick,draw,fill=orange!20,rectangle,minimum height=1.5cm,minimum width=2cm] (Adder) at (6,1) {加法器};
					\node[thick,draw,fill=blue!20,rectangle,minimum height=0.6cm,minimum width=1cm] (CLK) at (3.5,-0.2) {时钟和复位};
				\end{pgfonlayer}
				\begin{pgfonlayer}{foreground}
					\node[thick,draw,fill=white,fill=green!20,rectangle,minimum height=0.6cm,minimum width=3.4cm] (Interface) at (3.5,1) {接口};
					\draw [thick,-Latex] (CLK) -- (Interface.south);
				\end{pgfonlayer}
			\end{tikzpicture}
		}
		%\caption{使用接口进行通信的加法器和测试模块} \label{communication between dut and test using interface}
	\end{figure}

\end{frame}

\begin{frame}[t,fragile]{}

	\begin{enumerate}
		\item 接口使用关键字interface定义。
		\item 接口中可以使用连续赋值语句assign、过程块initial和always，也可以定义函数和任务。
		\item 接口封装了接口信号和与其相关的常用电平或时序操作。
		\item 接口信号通常定义为logic类型，带有多驱动的接口信号定义为wire类型。
		\item 接口是独立定义的，接口信号不需要给出信号方向。
	\end{enumerate}

	\lstinputlisting[language=SystemVerilog,numbers=left,linerange={4-12},consecutivenumbers=false]
	{src/ch4/sec1/1/intf.svh}

\end{frame}

\begin{frame}[t,fragile]{}

	\begin{enumerate}
		\item 接口主要在测试模块中使用。
	\end{enumerate}

	\lstinputlisting[language=SystemVerilog,numbers=left,linerange={4-21},consecutivenumbers=false]
	{src/ch4/sec1/1/test.sv}

\end{frame}

\begin{frame}[t,fragile]{}
	\begin{enumerate}
		\item 接口默认是静态类型，接口信号直接连接到DUT，因此通常将接口和DUT都例化在静态的顶层模块中。
	\end{enumerate}
	
	\lstinputlisting[language=SystemVerilog,numbers=left,linerange={5-8,26-35},consecutivenumbers=false]
	{src/ch4/sec1/1/top_tb.sv}

	\begin{enumerate}
		\item 简化信号连接。
		\item 便于信号改动。
	\end{enumerate}

\end{frame}

\subsection{模块端口} \label{Grouping Signals in an Interface Using Modports}

\begin{frame}[t,fragile]{模块端口(modport)}

	模块端口用来规定接口信号在模块中的方向，接口中可以声明多个模块端口。

	使用TEST后，测试模块只能访问TEST中的接口信号，并且只能读取input类型的clk、rst\_n和sum，不能对它们赋值。

	\lstinputlisting[language=SystemVerilog,numbers=left,linerange={4-15},consecutivenumbers=false]
	{src/ch4/sec1/2/intf.svh}

\end{frame}

\begin{frame}[t,fragile]{模块端口的使用方法}

	\begin{enumerate}
		\item 在测试模块的定义中指定模块端口名。这种做法可以将模块端口名隐藏在测试模块的定义中。
		\item 在例化测试模块时指定模块端口名，这种做法的好处是测试模块在例化时可以连接不同的模块端口。
	\end{enumerate}

	\lstinputlisting[language=SystemVerilog,numbers=left,linerange={4-4},consecutivenumbers=false]
	{src/ch4/sec1/2/test.sv}

	\lstinputlisting[language=SystemVerilog,numbers=left,linerange={5-5,34-35},consecutivenumbers=false]
	{src/ch4/sec1/3/top_tb.sv}

	使用模块端口后，测试模块只能访问模块端口中的接口信号，不能访问模块端口以外的接口信号。

\end{frame}

\section{同步信号的驱动与采样} \label{Interface Driving and Sampling}

\subsection{建立时间和保持时间} \label{subsec setup time and hold time}

\begin{frame}[t,fragile]{建立时间和保持时间}

	\begin{enumerate}
		\item clk为0时t0和t3打开，t1和t2关闭。建立时间定义为时钟沿到来前，触发器输入端的数据必须保持不变的最小时间。输入d需要使用一些时间来遍历路径d-w-x-y。
		\item clk为1时t0和t3关闭，t1和t2打开。保持时间定义为时钟沿到来后，触发器输入端的数据必须保持不变的最小时间。传输门需要时间打开或者关闭。期间d需要保持不变才能传输到w。
	\end{enumerate}

	\begin{figure}[!htb]
		\centering
		\tikzstyle{every node}=[font=\normalsize, scale=1.0]
		\begin{circuitikz}[american]
			\ctikzset{logic ports=ieee}
			\draw (0,0) node[ieee tgate, rotate = 0, anchor=in, name = t0]{}
			(t0.in) to[short] ++(0,0) node[left] {d}
			(t0.gate) to[short] ++(0,0) node[below] {$\overline{\textrm{clk}}$}
			(t0.notgate) to[short] ++(0,0) node[above] {clk}
			(t0.out) to[short] ++(0,0) node[above] {w}
			(t0.in) ++(0.6,0) node[color=red] {t0}

			(t0.out) to[short] ++(0,0) node[ieeestd not port, anchor=in, name = not0]{n0}
			(not0.out) to[short] ++(0,0) node[above] {x}

			(t0.out) to[short] ++(0,-0.5) node[ieee tgate, rotate = -90, anchor=in, name = t1]{}
			(t1.in) ++(0,-0.6) node[color=blue] {t1}
			(t1.gate) to[short] ++(0,0) node[left] {clk}
			(t1.notgate) to[short] ++(0,0) node[right] {$\overline{\textrm{clk}}$}
			(t1.out) to[short] ++(0,-0.5) node[ieeestd not port, rotate = 180, anchor=out, name = not1]{\rotatebox{180}{n1}}
			(not1.out) to[short] ++(0,0) node[below] {y}
			(not1.in) -| (not0.out)

			(not0.out) to[short] ++(0,0) node[ieee tgate, rotate = 0, anchor=in, name = t2]{}
			(t2.gate) to[short] ++(0,0) node[below] {clk}
			(t2.notgate) to[short] ++(0,0) node[above] {$\overline{\textrm{clk}}$}
			(t2.out) to[short] ++(0,0) node[above] {m}
			(t2.in) ++(0.6,0) node[color=blue] {t2}

			(t2.out) to[short] ++(0,0) node[ieeestd not port, anchor=in, name = not2]{n2}
			(not2.out) to[short] ++(0,0) node[above] {n}

			(t2.out) to[short] ++(0,-0.5) node[ieee tgate, rotate = -90, anchor=in, name = t3]{}
			(t3.in) ++(0,-0.6) node[color=red] {t3}
			(t3.gate) to[short] ++(0,0) node[left] {$\overline{\textrm{clk}}$}
			(t3.notgate) to[short] ++(0,0) node[right] {clk}
			(t3.out) to[short] ++(0,-0.5) node[ieeestd not port, rotate = 180, anchor=out, name = not3]{\rotatebox{180}{n3}}
			(not3.out) to[short] ++(0,0) node[below] {o}
			(not3.in) -| (not2.out)

			(not2.out) to[short] ++(0.5,0) node[right] {q}
			;
		\end{circuitikz}
		%\caption{D触发器} \label{fig d flip-flop}
	\end{figure}

\end{frame}

\subsection{时钟块} \label{Controlling Timing of Synchronous Signals with a Clocking Block}

\begin{frame}[t,fragile]{定义时钟块}

	\begin{enumerate}
		\item 接口中的时钟块使用关键字clocking定义。
		\item 每个时钟块信号都有明确的方向（input、output或inout）。
		\item 每个时钟块都包含一个时钟表达式，对应一个时钟域。
	\end{enumerate}

	\lstinputlisting[language=SystemVerilog,numbers=left,linerange={4-19},consecutivenumbers=false]
	{src/ch4/sec2/1/intf.svh}

\end{frame}

\begin{frame}[t,fragile]{使用时钟块}

	\begin{enumerate}
		\item 输出时钟块信号只能被非阻塞赋值，无法被读取。
		\item 输入时钟块信号只能被读取，无法被赋值。
	\end{enumerate}

	\lstinputlisting[language=SystemVerilog,numbers=left,linerange={4-21},consecutivenumbers=false]
	{src/ch4/sec2/1/test.sv}

\end{frame}

\subsection{时钟块的偏移} \label{Specifying Clocking Block Skew}

\begin{frame}[t,fragile]{时钟块变量}

	\begin{enumerate}
		\item 每个时钟块信号都对应一个同名的时钟块变量（clockvar），用来保存建立时间处的采样值或保持时间处的驱动值。
		\item 方向为input的时钟变量只允许读取，不能写入。
		\item 方向为output的时钟变量只允许写入，不能读取。
		\item 双向的时钟变量同时支持读写。
	\end{enumerate}

	\begin{table}[!htb]
		\centering%\captionsetup{font={small}}\small %small or scriptsize
		\caption{时钟块变量的读写权限} \label{accessing clocking signal in test module}
		\begin{tabular}{llll}
			\hline
			\rowcolor{black!10}信号方向 & 读权限 & 写权限 \\\hline
			input & 允许 & 禁止 \\\hline
			output & 禁止 & 允许 \\\hline
			inout & 允许 & 允许 \\\hline
		\end{tabular}
	\end{table}
\end{frame}

\begin{frame}[t,fragile]{输入偏移}

	\begin{enumerate}
		\item 输入偏移用于模拟建立时间，隐含为负值。测试平台在建立时间处采样响应，响应值会自动保存在时钟块变量中，然后在时钟事件处将其更新到输入时钟块信号。
		\item 默认输入偏移为\#1step，\#1step指定了输入信号在前一个时间片的最后时刻才被采样，此时DUT的所有输出信号都已经稳定。
	\end{enumerate}

	\begin{figure}[!htb]
		\centering
		\includegraphics[scale=0.8]{clocking_input_skew.pdf}
		%\caption{时钟块输入偏移 \label{clocking input skew}}
	\end{figure}

\end{frame}

\begin{frame}[t,fragile]{输出偏移}

	\begin{enumerate}
		\item 输出偏移用于模拟保持时间，隐含为正值。测试平台在时钟事件前更新（赋值）输出时钟块信号，驱动值会自动保存在时钟块变量中，然后在保持时间处将其驱动到接口信号。
		\item 时钟块的默认输出偏移为\#0。DUT的最佳驱动时间应该位于其所有输入信号都已经稳定之后。
	\end{enumerate}

	\begin{figure}[!htb]
		\centering
		\includegraphics[scale=0.8]{clocking_output_skew.pdf}
		%\caption{时钟块输出偏移 \label{clocking output skew}}
	\end{figure}

\end{frame}

\subsection{时钟块的偏移} \label{Specifying Delays Between the Design and Testbench}

\begin{frame}[t,fragile]{时钟块的偏移}

	使用default语句统一指定。

	\begin{lstlisting}[language=SystemVerilog,numbers=left,consecutivenumbers=false]
clocking cb @(posedge clk);
	default input #15ns output #10ns; // 建立时间为15ns，保持时间为10ns
	output a, b;
	input sum;
endclocking
\end{lstlisting}

	声明时钟块信号的同时单独指定

	\begin{lstlisting}[language=SystemVerilog,numbers=left,consecutivenumbers=false]
clocking cb @(posedge clk);
	output #10ns a, b;
	input #15ns sum;
endclocking
\end{lstlisting}

\end{frame}

\subsection{采样接口信号} \label{Interface Signal Sample}

\begin{frame}[t,fragile]{不同建立时间的采样}

	DUT在一些特定时间产生输出值

	\lstinputlisting[language=SystemVerilog,numbers=left,linerange={4-13},consecutivenumbers=false]
	{src/ch4/sec2/2/dut.sv}

	\begin{figure}[!htb]
		\centering%\captionsetup{font={small}}
		\scalebox{0.7}{
			\begin{tikztimingtable}
				clk & 7{5C} 1{1C}\\
				i\_intf.sum & 3D{0} 10D{1} 2D{2} 21D{3} \\
				\textcolor{red}{i\_intf.cb\_mon0.sum} & [red] 5U 10D{0} 10D{1} 11D{3} \\
				\textcolor{blue}{i\_intf.cb\_mon1.sum} & [blue] 5U 10D{1} 10D{2} 11D{3}\\
				\extracode
				%\tablerules
				\begin{pgfonlayer}{background}
					\vertlines[thick, help lines]{5,15,25,35}
					\vertlines[thick,red]{2,12,22}
					\vertlines[thick,dashed,blue]{4,14,24}
					\node[color=red] at (2,-7) {20};
					\node[color=red] at (12,-7) {120};
					\node[color=red] at (22,-7) {220};
					\node[color=blue] at (4,2) {40};
					\node[color=blue] at (14,2) {140};
					\node[color=blue] at (24,2) {240};
					\node at (5,-7) {50};
					\node at (15,-7) {150};
					\node at (25,-7) {250};
				\end{pgfonlayer}
			\end{tikztimingtable}
		}
		%\caption{接口信号与输入时钟块信号的关系} \label{sampling a clocking signal using default delay}
	\end{figure}

\end{frame}

\begin{frame}[t,fragile]{监控接口信号和时钟块信号}

	\lstinputlisting[language=SystemVerilog,numbers=left,linerange={4-15},consecutivenumbers=false]
	{src/ch4/sec2/2/intf.svh}

	\begin{figure}[!htb]
		\centering%\captionsetup{font={small}}
		\scalebox{0.7}{
			\begin{tikztimingtable}
				clk & 7{5C} 1{1C}\\
				i\_intf.sum & 3D{0} 10D{1} 2D{2} 21D{3} \\
				\textcolor{red}{i\_intf.cb\_mon0.sum} & [red] 5U 10D{0} 10D{1} 11D{3} \\
				\textcolor{blue}{i\_intf.cb\_mon1.sum} & [blue] 5U 10D{1} 10D{2} 11D{3}\\
				\extracode
				%\tablerules
				\begin{pgfonlayer}{background}
					\vertlines[thick, help lines]{5,15,25,35}
					\vertlines[thick,red]{2,12,22}
					\vertlines[thick,dashed,blue]{4,14,24}
					\node[color=red] at (2,-7) {20};
					\node[color=red] at (12,-7) {120};
					\node[color=red] at (22,-7) {220};
					\node[color=blue] at (4,2) {40};
					\node[color=blue] at (14,2) {140};
					\node[color=blue] at (24,2) {240};
					\node at (5,-7) {50};
					\node at (15,-7) {150};
					\node at (25,-7) {250};
				\end{pgfonlayer}
			\end{tikztimingtable}
		}
		%\caption{接口信号与输入时钟块信号的关系} \label{sampling a clocking signal using default delay}
	\end{figure}

\end{frame}

\subsection{驱动接口信号} \label{Driving Interface Signals Through a Clocking Block}

\begin{frame}[t,fragile]{避免异步方式更新时钟块信号}

	\lstinputlisting[language=SystemVerilog,numbers=left,linerange={4-11},consecutivenumbers=false]
	{src/ch4/sec2/3/test.sv}

	\begin{figure}[!htb]
		\centering%\captionsetup{font={small}}
		\scalebox{0.7}{
			\begin{tikztimingtable}
				clk & 9{5C} 1{3C}\\
				cb\_drv.a & 4U 11D{1} 12D{2} 21D{3} \\
				\textcolor{red}{a} & [red] 6U 10D{1} 20D{2} 12D{3}\\
				cb\_mon.a & 15U 10D{1} 20D{2} 3D{3}\\
				\extracode
				%\tablerules
				\begin{pgfonlayer}{background}
					\vertlines[thick, help lines]{5,15,25,35,45}
					%\vertlines[thick,dashed,blue]{4,15,27}
					\vertlines[thick,red]{6,16,26,36,46}
					\node[color=red] at (6,2) {60};
					\node[color=red] at (16,2) {160};
					\node[color=red] at (26,2) {260};
					\node[color=red] at (36,2) {360};
					\node[color=red] at (46,2) {460};
					\node at (5,-7) {50};
					\node at (15,-7) {150};
					\node at (25,-7) {250};
					\node at (35,-7) {350};
					\node at (45,-7) {450};
					%\vertlines[thick,dashed,blue]{4,14,24}
				\end{pgfonlayer}
			\end{tikztimingtable}
		}
		%\caption{使用异步的方式更新输出时钟块信号cb\_drv.a} \label{Fig Driving a synchronous interface}
	\end{figure}

\end{frame}

\begin{frame}[t,fragile]{指定接口中的输出偏移}

	\lstinputlisting[language=SystemVerilog,numbers=left,linerange={4-17}]
	{src/ch4/sec2/3/intf.svh}

	\begin{figure}[!htb]
		\centering%\captionsetup{font={small}}
		\scalebox{0.7}{
			\begin{tikztimingtable}
				clk & 9{5C} 1{3C}\\
				cb\_drv.a & 4U 11D{1} 12D{2} 21D{3} \\
				\textcolor{red}{a} & [red] 6U 10D{1} 20D{2} 12D{3}\\
				cb\_mon.a & 15U 10D{1} 20D{2} 3D{3}\\
				\extracode
				%\tablerules
				\begin{pgfonlayer}{background}
					\vertlines[thick, help lines]{5,15,25,35,45}
					%\vertlines[thick,dashed,blue]{4,15,27}
					\vertlines[thick,red]{6,16,26,36,46}
					\node[color=red] at (6,2) {60};
					\node[color=red] at (16,2) {160};
					\node[color=red] at (26,2) {260};
					\node[color=red] at (36,2) {360};
					\node[color=red] at (46,2) {460};
					\node at (5,-7) {50};
					\node at (15,-7) {150};
					\node at (25,-7) {250};
					\node at (35,-7) {350};
					\node at (45,-7) {450};
					%\vertlines[thick,dashed,blue]{4,14,24}
				\end{pgfonlayer}
			\end{tikztimingtable}
		}
		%\caption{使用异步的方式更新输出时钟块信号cb\_drv.a} \label{Fig Driving a synchronous interface}
	\end{figure}

\end{frame}

\subsection{接口信号同步} \label{Interface Synchronization}

\begin{frame}[t,fragile]{同步方式更新输出时钟块信号}

	使用异步的方式更新时钟块信号不能保证所有值都被DUT接收到。推荐在驱动语句前使用周期延时保证时钟块信号在时钟沿改变。

	\begin{lstlisting}[language=SystemVerilog,numbers=left,consecutivenumbers=false]
repeat(2) @i_intf.cb i_intf.cb_drv.a <= 0; // 等待2个时钟周期后赋值
##2 i_intf.cb_drv.a <= 0; // 等待2个时钟周期后赋值
##3; // 错误，##必须配合时钟块信号的赋值使用
\end{lstlisting}

	\begin{lstlisting}[language=SystemVerilog,numbers=left]
module automatic test (intf.TEST i_intf);
	initial begin
		@i_intf.cb;                  // 等待时钟块中clk的上升沿
		@i_intf.cb.sum[0];           // 等待sum[0]的上下沿
		@(posedge i_intf.cb.sum[0]); // 等待sum[0]的上升沿
		wait(i_intf.cb.sum == 5'hf); // 等待表达式成立
	end
endmodule
\end{lstlisting}

\end{frame}

\subsection{接口中的双向信号} \label{Bidirectional Signals in the Interface}

\begin{frame}[t,fragile]{多驱动}

	\begin{enumerate}
		\item 接口中双向信号必须定义成wire类型
		\item 在时钟块中将其声明成inout类型
		\item inout类型的时钟块信号可以直接在过程语句中被赋值和读取
	\end{enumerate}

	\lstinputlisting[language=SystemVerilog,numbers=left,linerange={4-10},consecutivenumbers=false]
	{src/ch4/sec2/4/test.sv}

\end{frame}

\begin{frame}[t,fragile]{}

	\lstinputlisting[language=SystemVerilog,numbers=left,linerange={12-35},consecutivenumbers=false]
	{src/ch4/sec2/4/test.sv}

\end{frame}

\end{document}
